package org.lansir.af.ui;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.lansir.af.R;
import org.lansir.af.gtalk.service.Contact;
import org.lansir.af.gtalk.service.aidl.IRoster;
import org.lansir.af.gtalk.service.aidl.IXmppFacade;
import org.lansir.af.gtalk.utils.SortedList;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.CheckBox;
import android.widget.ExpandableListView;
import android.widget.ExpandableListView.OnChildClickListener;
import android.widget.TextView;

public class ScheduleContactFragment extends CommonFragment {
	private static final String TAG = "ScheduleContactFragment";
	public static final String RESULT_SELECTED_PARTICIPATOR = "SelectedParticipators";

	private static final Intent SERVICE_INTENT = new Intent();
	static {
		SERVICE_INTENT.setComponent(new ComponentName("org.lansir.af", "org.lansir.af.gtalk.GtalkService"));
	}

	private ExpandableListView etvScheduleContactList;
	private GtalkContactListAdapter mGtalkContactListAdapter;

	private GtalkServiceConnection mServiceConn;
	private final Map<String, List<Contact>> mContactOnGroup = new HashMap<String, List<Contact>>();
	private final List<String> mListGroup =  new ArrayList<String>();
	private Set<Contact> mSelectedContactCache;
	private Set<String> mSelectedGroupCache;
	private final ComparatorContactListByStatusAndName<Contact> mComparator = new ComparatorContactListByStatusAndName<Contact>();
	private boolean mBinded = false;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		mSelectedContactCache = new HashSet<Contact>();
		mSelectedGroupCache = new HashSet<String>();
		mServiceConn = new GtalkServiceConnection();
		this.setHasOptionsMenu(true);
		if(!mGtalkApplication.isConnected()){
			this.startActivityForResult(new Intent("org.lansir.af.intent.action.ACTION_GTALK"), REQUEST_CODE_DEFAULT);
		}
	}

	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
		View viewRoot = inflater.inflate(R.layout.fragment_schedule_contactlist, null);
		etvScheduleContactList = (ExpandableListView) viewRoot.findViewById(R.id.etvScheduleContactList);
		mGtalkContactListAdapter = new GtalkContactListAdapter(inflater);
		etvScheduleContactList.setAdapter(mGtalkContactListAdapter);		
		etvScheduleContactList.setOnChildClickListener(new OnGtalkContactClickListener());

		return viewRoot;
	}

	@Override
	public void onResume() {
		super.onResume();
		if (!mBinded && mGtalkApplication.isConnected()) {
			mBinded = getActivity().bindService(SERVICE_INTENT, mServiceConn, Context.BIND_AUTO_CREATE);
		}
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void onPause() {
		super.onPause();
		if (mBinded) {
			getActivity().unbindService(mServiceConn);
			mBinded = false;
		}

	}
	
	@Override
	public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
		inflater.inflate(R.menu.schedule_activity_menu_items, menu);
		super.onCreateOptionsMenu(menu, inflater);
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		if (item.getItemId() == R.id.menu_save) {
			Intent intent = new Intent();
			ArrayList<Contact> mListSelectedContact = new ArrayList<Contact>();
			mListSelectedContact.addAll(mSelectedContactCache);
			intent.putParcelableArrayListExtra(RESULT_SELECTED_PARTICIPATOR, mListSelectedContact);
			
			getActivity().setResult(Activity.RESULT_OK, intent);
			getActivity().finish();

			return true;
		}
		return super.onOptionsItemSelected(item);
	}	
	
	

	@Override
	public void onActivityResult(int requestCode, int resultCode, Intent data) {
		if(requestCode == REQUEST_CODE_DEFAULT && !mGtalkApplication.isConnected()){
			getActivity().setResult(Activity.RESULT_CANCELED);
			getActivity().finish();
		}
		super.onActivityResult(requestCode, resultCode, data);
	}



	private class GtalkServiceConnection implements ServiceConnection {

		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			IXmppFacade mXmppFacade = IXmppFacade.Stub.asInterface(service);
			IRoster mRoster;
			try {
				mRoster = mXmppFacade.getRoster();
				if (mRoster != null) {
					List<String> tmpGroupList = mRoster.getGroupsNames();
					Collections.sort(tmpGroupList);
					mListGroup.clear();
					mListGroup.add(getString(R.string.contact_list_all_contact));
					mListGroup.addAll(tmpGroupList);
					mListGroup.add(getString(R.string.contact_list_no_group));
					assignContactToGroups(mRoster.getContactList(), tmpGroupList);
					makeSortedList(mContactOnGroup);
					mGtalkContactListAdapter.notifyDataSetChanged();

					// String group =
					// getString(R.string.contact_list_all_contact);
					// buildContactList(group);

				}
			} catch (RemoteException e) {
				e.printStackTrace();
			}

		}

		@Override
		public void onServiceDisconnected(ComponentName name) {
			mListGroup.clear();
			mContactOnGroup.clear();
			mBinded = false;
		}

		/**
		 * Assign the differents contact to their groups. This methods will fill
		 * the mContactOnGroup map.
		 * 
		 * @param contacts
		 *            list of contacts
		 * @param groupNames
		 *            list of existing groups
		 */
		private void assignContactToGroups(List<Contact> contacts, List<String> groupNames) {

			mContactOnGroup.clear();
			List<Contact> all = new LinkedList<Contact>();
			List<Contact> noGroups = new LinkedList<Contact>();
			for (String group : groupNames) {
				mContactOnGroup.put(group, new LinkedList<Contact>());
			}
			for (Contact c : contacts) {

				all.add(c);
				List<String> groups = c.getGroups();
				if (groups.isEmpty())
					noGroups.add(c);
				else {
					for (String currentGroup : groups) {
						List<Contact> contactsByGroups = mContactOnGroup.get(currentGroup);
						contactsByGroups.add(c);
					}
				}
			}
			mContactOnGroup.put(getString(R.string.contact_list_no_group), noGroups);
			mContactOnGroup.put(getString(R.string.contact_list_all_contact), all);
		}

		/**
		 * Make the List of the map became Insertion sorted list.
		 * 
		 * @param map
		 *            the map to convert.
		 */
		private void makeSortedList(Map<String, List<Contact>> map) {
			for (Map.Entry<String, List<Contact>> entry : map.entrySet()) {
				List<Contact> l = entry.getValue();
				entry.setValue(new SortedList<Contact>(l, mComparator));
			}
		}

	}

	private class OnGtalkContactClickListener implements OnChildClickListener {

		@Override
		public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
			GtalkContactListAdapter.ViewHolder buddyViewHolder = (GtalkContactListAdapter.ViewHolder) v.getTag();
			CheckBox checkbox = buddyViewHolder.cbContactList;
			final Contact buddy = mContactOnGroup.get(mListGroup.get(groupPosition)).get(childPosition);
			if (!checkbox.isChecked()) {
				mSelectedContactCache.add(buddy);
				checkbox.setChecked(true);
			} else {
				mSelectedContactCache.remove(buddy);
				checkbox.setChecked(false);
			}
			return false;
		}

	}
	
	private static class ComparatorContactListByStatusAndName<T> implements Comparator<T> {
		/**
		 * Constructor.
		 */
		public ComparatorContactListByStatusAndName() {
		}

		@Override
		public int compare(T c1, T c2) {
			if (((Contact) c1).getStatus() < ((Contact) c2).getStatus()) {
				return 1;
			} else if (((Contact) c1).getStatus() > ((Contact) c2).getStatus()) {
				return -1;
			} else
				return ((Contact) c1).getName().compareToIgnoreCase(((Contact) c2).getName());
		}
	}

	private class GtalkContactListAdapter extends BaseExpandableListAdapter {

		private LayoutInflater inflater;

		public GtalkContactListAdapter(LayoutInflater inflater) {
			this.inflater = inflater;
		}

		@Override
		public Object getChild(int groupPosition, int childPosition) {
			return mContactOnGroup.get(mListGroup.get(groupPosition)).get(childPosition);
		}

		@Override
		public long getChildId(int groupPosition, int childPosition) {
			Contact contact = (Contact) getChild(groupPosition, childPosition);
			return contact.getID();
		}

		@Override
		public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
			ViewHolder viewHolder;
			if (convertView == null) {
				convertView = inflater.inflate(R.layout.schedule_contact_list_contact_item, null);	
				viewHolder = new ViewHolder();
				viewHolder.tvContactListName = (TextView) convertView.findViewById(R.id.tvContactListParticipatorName);
				viewHolder.cbContactList = (CheckBox) convertView.findViewById(R.id.cbContactListParticipatorCheck);

				convertView.setTag(viewHolder);
			} else {
				viewHolder = (ViewHolder) convertView.getTag();
			}
			final Contact contact = mContactOnGroup.get(mListGroup.get(groupPosition)).get(childPosition);
			viewHolder.tvContactListName.setText(contact.getName());
			viewHolder.cbContactList.setChecked(mSelectedContactCache.contains(contact));
			return convertView;
		}

		@Override
		public int getChildrenCount(int groupPosition) {
			return mContactOnGroup.get(mListGroup.get(groupPosition)).size();
		}

		@Override
		public Object getGroup(int groupPosition) {
			return mListGroup.get(groupPosition);
		}

		@Override
		public int getGroupCount() {
			return mListGroup.size();
		}

		@Override
		public long getGroupId(int groupPosition) {
			return mListGroup.get(groupPosition).hashCode();
		}

		@Override
		public View getGroupView(final int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
			ViewHolder viewHolder;
			final String group = mListGroup.get(groupPosition);
			if (convertView == null) {
				convertView = inflater.inflate(R.layout.schedule_contact_list_group_item, null);
	
				viewHolder = new ViewHolder();
				viewHolder.tvContactListName = (TextView) convertView.findViewById(R.id.tvContactListGroupName);
				viewHolder.cbContactList = (CheckBox) convertView.findViewById(R.id.cbContactListGroupCheck);
			
				
//				viewHolder.cbContactList.setOnCheckedChangeListener(new OnCheckedChangeListener() {
//
//					@Override
//					public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
//						
//					}
//
//				});
				convertView.setTag(viewHolder);
			} else {
				viewHolder = (ViewHolder) convertView.getTag();
			}

			viewHolder.tvContactListName.setText(mListGroup.get(groupPosition));
			Log.v(TAG, "contain:group:" + group + "->" + mSelectedGroupCache.contains(group));
			viewHolder.cbContactList.setChecked(mSelectedGroupCache.contains(group));
			final CheckBox check = viewHolder.cbContactList;
			viewHolder.cbContactList.setOnClickListener(new OnClickListener(){

				@Override
				public void onClick(View v) {
					if (check.isChecked()) {
						mSelectedGroupCache.add(group);
						for(Contact c : mContactOnGroup.get(group)){
							mSelectedContactCache.add(c);
						}
						etvScheduleContactList.expandGroup(groupPosition);
					} else {
						mSelectedGroupCache.remove(group);
						for(Contact c : mContactOnGroup.get(group)){
							mSelectedContactCache.remove(c);
						}
						etvScheduleContactList.collapseGroup(groupPosition);
					}
					mGtalkContactListAdapter.notifyDataSetChanged();
					Log.v(TAG, "groupPosition:" + groupPosition);
				}
				
			});
			

			return convertView;
		}

		@Override
		public boolean hasStableIds() {

			return false;
		}

		@Override
		public boolean isChildSelectable(int groupPosition, int childPosition) {

			return true;
		}

		public class ViewHolder {
			public TextView tvContactListName;
			public CheckBox cbContactList;
		}

	}
	
	

}
